package com.zbkj.service.service.impl;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zbkj.common.config.CrmebConfig;
import com.zbkj.common.constants.RedisConstants;
import com.zbkj.common.netty.AcceptDataContent;
import com.zbkj.common.netty.AcceptMessage;
import com.zbkj.common.netty.SendDataContent;
import com.zbkj.common.netty.SendMessage;
import com.zbkj.common.token.FrontTokenComponent;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.common.utils.RequestUtil;
import com.zbkj.common.vo.LoginUserVo;
import com.zbkj.service.service.SendMessageService;
import com.zbkj.service.util.ResponseRouterUtil;
import com.zbkj.service.websocket.ChannelQueueDTO;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class SendMessageServiceImpl implements SendMessageService {

    private final RedisUtil redisUtil;
    private final FrontTokenComponent  frontTokenComponent;
    private final ObjectMapper objectMapper;
    private final CrmebConfig crmebConfig;
    private final String TOKEN_PLATFORM_START_PREFIX = "platform";
    private final String TOKEN_PLATFORM_REDIS = "TOKEN:ADMIN:PLATFORM:";

    /**
     * 客服聊天登录
     *
     * @param acceptDataContent
     */
    @Override
    public Boolean login(AcceptDataContent acceptDataContent, Channel channel) {
        try {
            if (ObjUtil.isEmpty(acceptDataContent.getExtendField())) {
                this.sendMessage(acceptDataContent, channel, "绑定失败");
                return false;
            }
            String channelId = channel.id().asLongText();

            // 用户登录
            if (acceptDataContent.getExtendField().startsWith(RedisConstants.WEB_TOKEN_USER_NORMAL_KEY)) {
                String redisToken = frontTokenComponent.processWebTokenToRedisToken(acceptDataContent.getExtendField());
                Integer userId = redisUtil.get(redisToken);
                if (ObjUtil.isNull(userId)) {
                    this.sendMessage(acceptDataContent, channel, "绑定失败");
                    return false;
                }

                String userIdStr = "1_"+userId;
                redisUtil.hset(RedisConstants.ORDINARY_USERS_CHANNEL, userIdStr, channelId);
                redisUtil.hset(RedisConstants.RELATION_CHANNEL_USER, channelId, userIdStr);
                redisUtil.hset(RedisConstants.RELATION_USER_CHANNEL, userIdStr, channelId);
                this.sendMessage(acceptDataContent, channel, "绑定成功");
                return true;
            }

            // 平台客服登录
            if (acceptDataContent.getExtendField().startsWith(TOKEN_PLATFORM_START_PREFIX)) {
                String redisToken = TOKEN_PLATFORM_REDIS + acceptDataContent.getExtendField().replace(TOKEN_PLATFORM_START_PREFIX, "");
                Object obj = redisUtil.get(redisToken);
                if (ObjUtil.isNull(obj)) {
                    this.sendMessage(acceptDataContent, channel, "绑定失败");
                    return false;
                }
                LoginUserVo admin = (LoginUserVo) obj;
                String userIdStr = "2_"+admin.getUser().getId();
                redisUtil.hset(RedisConstants.CUSTOMER_SERVICE_CHANNEL, userIdStr, channelId);
                redisUtil.hset(RedisConstants.RELATION_CHANNEL_USER, channelId, userIdStr);
                redisUtil.hset(RedisConstants.RELATION_USER_CHANNEL, userIdStr, channelId);
                this.sendMessage(acceptDataContent, channel, "绑定成功");
                return true;
            }
        } catch (Exception e) {
            log.error("Netty Channel 绑定用户异常", e);
        }
        this.sendMessage(acceptDataContent, channel, "绑定失败");
        return false;
    }


    public void logout(Channel channel) {
        String asLongText = channel.id().asLongText();
        String userIdStr = (String) redisUtil.hget(RedisConstants.RELATION_CHANNEL_USER, asLongText);
        if (StrUtil.isNotBlank(userIdStr)) {
            String[] split = userIdStr.split("_");
            if (split.length == 2){
                String type = split[0];
                String userId = split[1];
                if ("1".equals(type)) {
                    redisUtil.hmDelete(RedisConstants.ORDINARY_USERS_CHANNEL,  userId);
                } else {
                    redisUtil.hmDelete(RedisConstants.CUSTOMER_SERVICE_CHANNEL,  userId);
                }
                log.info("正常退出的channelId是:{},正常退出的userId是:{}", asLongText, userId);
            }
        }
    }


    /**
     * 转发消息
     */
    @Override
    public void sendMessage(AcceptDataContent acceptDataContent) {
        String userIdStr;
        if (1 == acceptDataContent.getToUserType()) {
            userIdStr  = "1_" + acceptDataContent.getUserInfo().getUserId();
        } else {
            userIdStr = "2_" + acceptDataContent.getCustomerServiceInfo().getUserId();
        }
        String channelId = (String) redisUtil.hget(RedisConstants.RELATION_USER_CHANNEL, userIdStr);

        this.sendMessage(acceptDataContent, channelId);
//        if (1 == acceptDataContent.getUserType()) {
//            //查询客服是否在线
//            String status = (String) redisUtil.hget(RedisConstants.CUSTOMER_SERVICE_STATUS, acceptDataContent.getCustomerServiceInfo().getUserId().toString());
//            //在线
//            if (RedisConstants.ONLINE.equals(status)) {
//                //发送消息
//                sendMessage(acceptDataContent, acceptDataContent.getMessageType(), acceptDataContent.getUserType());
//
//            }
//            //离线
//            else {
//
//            }
//
//        }

    }

    private void sendMessage(AcceptDataContent acceptDataContent, String channelId) {
        AcceptDataContent bean = acceptDataContent;
        try {
            String jsonStr = JSONUtil.toJsonStr(acceptDataContent);
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            jsonStr = ResponseRouterUtil.filter(jsonStr, RequestUtil.getUri(request), crmebConfig);
            bean = JSONUtil.toBean(jsonStr, AcceptDataContent.class);
        } catch (Exception e) {
            log.error("转换路径异常", e);
        }
        ChannelQueueDTO dto = new ChannelQueueDTO().setChannelId(channelId).setAcceptDataContent(bean);

        redisUtil.lPush(RedisConstants.CHANNEL_MESSAGE_QUEUE_KEY, dto);
    }

    public void sendMessage(AcceptDataContent acceptDataContent, Channel channel) {
        //获取channel消息通道
        if (channel != null) {

            SendMessage message = new SendMessage()
                .setMessageContent(acceptDataContent.getAcceptMessage().getMessageContent())
                .setAssistantMessage(acceptDataContent.getAcceptMessage().getAssistantMessage());
            SendDataContent sendDataContent = new SendDataContent()
                    .setType(acceptDataContent.getMessageType())
                    .setSendMessage(message)
                    .setUserInfo(acceptDataContent.getUserInfo())
                    .setCustomerServiceInfo(acceptDataContent.getCustomerServiceInfo())
                    .setExtendField(acceptDataContent.getExtendField());
            //发送消息
            try {
                String json = objectMapper.writeValueAsString(sendDataContent);
                ChannelFuture channelFuture = channel.writeAndFlush(new TextWebSocketFrame(json));
                //监听消息回执
                channelFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        Throwable cause = future.cause();
                        if (cause != null) {
                            // 处理异常情况
                        } else {
                            // 写入Socket成功后，Netty会通知到这里
                            log.info("任务结果:{}....,任务是否成功{}", channelFuture.getNow(), channelFuture.isSuccess());
//                            //封装消息
//                            EsMessage esMessage = new EsMessage();
//                            if (1 == acceptDataContent.getUserType()) {
//                                esMessage.setSendUserId(acceptDataContent.getUserInfo().getUserId())
//                                        .setAcceptUserId(acceptDataContent.getCustomerServiceInfo().getUserId());
//                            } else {
//                                esMessage.setSendUserId(acceptDataContent.getCustomerServiceInfo().getUserId())
//                                        .setAcceptUserId(acceptDataContent.getUserInfo().getUserId());
//                            }
//                            esMessage.setMessageContent(acceptDataContent.getAcceptMessage().getMessageContent())
//                                    .setType(messageType)
//                                    .setCreateTime(System.currentTimeMillis())
//                                    .setIdRead(0);
//                            //将消息添加到es
//                            esMessageMapper.insert(esMessage);
//                            //标记消息未读数
//                            if (1 == acceptDataContent.getUserType()) {
//                                redisUtil.incr(StrUtil.format(RedisConstants.CUSTOMER_SERVICE_NOT_READ_NUMBER,
//                                        acceptDataContent.getCustomerServiceInfo().getUserId(), acceptDataContent.getUserInfo().getUserId()), 1);
//                            } else {
//                                redisUtil.incr(StrUtil.format(RedisConstants.ORDINARY_USERS_NOT_READ_NUMBER, acceptDataContent.getUserInfo().getUserId()), 1);
//                            }
                        }
                    }
                });
            } catch (Exception e) {
                log.info("获取发送消息异常......");
            } finally {

            }
        } else {
            log.info("未找到{}长连接channel......", acceptDataContent.getUserType() == 1 ? "客服端" : "用户端");
        }
    }

    private void sendMessage(AcceptDataContent acceptDataContent, Channel channel, String message) {
        AcceptMessage acceptMessage = new AcceptMessage().setMessageContent(message);
        acceptDataContent.setAcceptMessage(acceptMessage);
        this.sendMessage(acceptDataContent, channel);
    }

}

